{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import json\n",
    "import math\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import pickle\n",
    "\n",
    "import tensorflow as tf\n",
    "import ray\n",
    "from ray import tune\n",
    "from ray.rllib.agents.ppo import PPOAgent\n",
    "from neurocuts_env import NeuroCutsEnv\n",
    "from run_neurocuts import on_episode_end\n",
    "from ray.tune.registry import register_env\n",
    "from ray.rllib.models import ModelCatalog\n",
    "from mask import PartitionMaskModel\n",
    "from tree import Node\n",
    "from tree import load_rules_from_file\n",
    "\n",
    "%load_ext autoreload\n",
    "%autoreload 2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 09:27:04,537\tINFO node.py:439 -- Process STDOUT and STDERR is being redirected to /tmp/ray/session_2019-03-30_09-27-04_98085/logs.\n",
      "2019-03-30 09:27:04,648\tINFO services.py:364 -- Waiting for redis server at 127.0.0.1:55483 to respond...\n",
      "2019-03-30 09:27:04,763\tINFO services.py:364 -- Waiting for redis server at 127.0.0.1:33516 to respond...\n",
      "2019-03-30 09:27:04,766\tINFO services.py:761 -- Starting Redis shard with 3.44 GB max memory.\n",
      "2019-03-30 09:27:04,782\tINFO services.py:1449 -- Starting the Plasma object store with 5.15 GB memory using /tmp.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'node_ip_address': None,\n",
       " 'redis_address': '192.168.1.161:55483',\n",
       " 'object_store_address': '/tmp/ray/session_2019-03-30_09-27-04_98085/sockets/plasma_store',\n",
       " 'webui_url': None,\n",
       " 'raylet_socket_name': '/tmp/ray/session_2019-03-30_09-27-04_98085/sockets/raylet'}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### Init ###\n",
    "ray.init()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "rules = os.path.abspath(\"classbench/{}\".format(\"fw5_1k\"))\n",
    "dump_dir = \"/tmp/neurocuts_out\"\n",
    "reward_shape = \"linear\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Setup ###\n",
    "register_env(\n",
    "    \"tree_env\", lambda env_config: NeuroCutsEnv(\n",
    "        env_config[\"rules\"],\n",
    "        max_depth=env_config[\"max_depth\"],\n",
    "        max_actions_per_episode=env_config[\"max_actions\"],\n",
    "        dump_dir=env_config[\"dump_dir\"],\n",
    "        depth_weight=env_config[\"depth_weight\"],\n",
    "        reward_shape=env_config[\"reward_shape\"],\n",
    "        partition_mode=env_config[\"partition_mode\"]))\n",
    "ModelCatalog.register_custom_model(\"mask\", PartitionMaskModel)\n",
    "\n",
    "config =  {\n",
    "        \"num_gpus\": 0,\n",
    "        \"num_workers\": 3,\n",
    "        \"sgd_minibatch_size\": 100,\n",
    "        \"sample_batch_size\": 200,\n",
    "        \"train_batch_size\": 1000,\n",
    "        \"batch_mode\": \"complete_episodes\",\n",
    "        \"observation_filter\": \"NoFilter\",\n",
    "        \"model\": {\n",
    "            \"custom_model\": \"mask\",\n",
    "            \"fcnet_hiddens\": [512, 512],\n",
    "        },\n",
    "        \"vf_share_layers\": True,\n",
    "        \"entropy_coeff\": 0.01,\n",
    "        \"callbacks\": {\n",
    "            \"on_episode_end\": tune.function(on_episode_end),\n",
    "        },\n",
    "        \"env_config\": {\n",
    "            \"dump_dir\": dump_dir,\n",
    "            \"partition_mode\": None,\n",
    "            \"reward_shape\": reward_shape,\n",
    "            \"max_depth\": 100,\n",
    "            \"max_actions\": 1000,\n",
    "            \"depth_weight\": 1.0,\n",
    "            \"rules\": rules,\n",
    "        },\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# file = \"/Users/yitianzou/ray_results/neurocuts_None/PPO_tree_env_1_rules=_Users_yitianzou_neurocuts-code_classbench_acl5_1k,sample_batch_size=400_2019-02-20_15-30-42uewkqv_l/checkpoint_1/checkpoint-1\"\n",
    "# env = NeuroCutsEnv(rules_file=\"classbench/acl5_1k\")\n",
    "# agent = PPOAgent(env=\"tree_env\", config=config)\n",
    "# agent.restore(file)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 10:04:00,561\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 0 on CPU (please ignore any CUDA init errors)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Colocations handled automatically by placer.\n",
      "WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.random.categorical instead.\n",
      "WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Use tf.cast instead.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "  \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "Deprecated in favor of operator or tf.math.divide.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 10:04:01,628\tINFO multi_gpu_optimizer.py:74 -- LocalMultiGPUOptimizer devices ['/cpu:0']\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m 2019-03-30 10:04:06,439\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 1 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m 2019-03-30 10:04:06.440239: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m 2019-03-30 10:04:06,439\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 3 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m 2019-03-30 10:04:06.440425: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m 2019-03-30 10:04:06,438\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 2 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m 2019-03-30 10:04:06.440439: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 10:04:06,949\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 0 on CPU (please ignore any CUDA init errors)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98106)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98100)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98101)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 10:04:08,229\tINFO multi_gpu_optimizer.py:74 -- LocalMultiGPUOptimizer devices ['/cpu:0']\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m 2019-03-30 10:04:09,768\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 1 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m 2019-03-30 10:04:09.770128: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m 2019-03-30 10:04:09,772\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 3 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m 2019-03-30 10:04:09.774281: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m 2019-03-30 10:04:09,765\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 2 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m 2019-03-30 10:04:09.767237: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98104)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98103)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98102)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 10:04:12,084\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 0 on CPU (please ignore any CUDA init errors)\n",
      "2019-03-30 10:04:13,097\tINFO multi_gpu_optimizer.py:74 -- LocalMultiGPUOptimizer devices ['/cpu:0']\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m 2019-03-30 10:04:14,574\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 1 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m 2019-03-30 10:04:14.576373: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m 2019-03-30 10:04:14,573\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 3 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m 2019-03-30 10:04:14.573995: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m 2019-03-30 10:04:14,573\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 2 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m 2019-03-30 10:04:14.574183: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98098)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98099)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98108)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 10:04:16,722\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 0 on CPU (please ignore any CUDA init errors)\n",
      "2019-03-30 10:04:17,849\tINFO multi_gpu_optimizer.py:74 -- LocalMultiGPUOptimizer devices ['/cpu:0']\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m 2019-03-30 10:04:19,284\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 1 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m 2019-03-30 10:04:19.285397: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m 2019-03-30 10:04:19,311\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 2 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m 2019-03-30 10:04:19.313001: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m 2019-03-30 10:04:19,320\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 3 on CPU (please ignore any CUDA init errors)\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m 2019-03-30 10:04:19.321945: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Colocations handled automatically by placer.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/ray/rllib/models/action_dist.py:114: multinomial (from tensorflow.python.ops.random_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Use tf.random.categorical instead.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/array_grad.py:425: to_int32 (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Use tf.cast instead.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/gradients_impl.py:110: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m   \"Converting sparse IndexedSlices to a dense Tensor of unknown shape. \"\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98105)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98109)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m WARNING:tensorflow:From /Users/yitianzou/anaconda3/lib/python3.7/site-packages/tensorflow/python/ops/math_grad.py:102: div (from tensorflow.python.ops.math_ops) is deprecated and will be removed in a future version.\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Instructions for updating:\n",
      "\u001b[2m\u001b[36m(pid=98107)\u001b[0m Deprecated in favor of operator or tf.math.divide.\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "2019-03-30 10:04:21,390\tINFO policy_evaluator.py:275 -- Creating policy evaluation worker 0 on CPU (please ignore any CUDA init errors)\n",
      "2019-03-30 10:04:22,533\tINFO multi_gpu_optimizer.py:74 -- LocalMultiGPUOptimizer devices ['/cpu:0']\n"
     ]
    }
   ],
   "source": [
    "# directory = \"/Users/yitianzou/ray_results/neurocuts_None/PPO_tree_env_0_2019-03-08_23-48-42pb2k3nsd\"\n",
    "# directory = \"/Users/yitianzou/ray_results/neurocuts_None/PPO_tree_env_0_2019-03-20_20-38-09ixikyqq8/\"\n",
    "directory = \"/Users/yitianzou/ray_results/neurocuts_None/PPO_tree_env_0_2019-03-27_16-29-19mwsnjoc7\"\n",
    "env = NeuroCutsEnv(rules_file=rules)\n",
    "\n",
    "agent_1 = PPOAgent(env=\"tree_env\", config=config)\n",
    "agent_1.restore(directory+\"/checkpoint_1/checkpoint-1\")\n",
    "agent_1M = PPOAgent(env=\"tree_env\", config=config)\n",
    "agent_1M.restore(directory+\"/checkpoint_23/checkpoint-23\")\n",
    "agent_2M = PPOAgent(env=\"tree_env\", config=config)\n",
    "agent_2M.restore(directory+\"/checkpoint_54/checkpoint-54\")\n",
    "agent_4M = PPOAgent(env=\"tree_env\", config=config)\n",
    "agent_4M.restore(directory+\"/checkpoint_136/checkpoint-136\")\n",
    "agent_8M = PPOAgent(env=\"tree_env\", config=config)\n",
    "agent_8M.restore(directory+\"/checkpoint_318/checkpoint-318\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'experiment_id': '724ddabdf2dc4cbf9d2d023e48259202', 'iteration': 318, 'timesteps_total': 8005017, 'time_total': 77897.14273428917, 'episodes_total': 1643, 'saved_as_dict': False}\n"
     ]
    }
   ],
   "source": [
    "meta = directory + \"/checkpoint_318/checkpoint-318.tune_metadata\"\n",
    "with open(meta, 'rb') as f:\n",
    "    text = pickle.load(f)\n",
    "print(text)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## TODOS\n",
    "1. Verify that after num-fast # iterations, reward (memory_access) has converged to around 10 - DONE\n",
    "2. Generate distribution of (src, dst) - DONE\n",
    "3. Make contour for 1st checkpoint - DONE\n",
    "4. Vectorize _value - DONE\n",
    "5. Get checkpoints + run for different ones - DONE\n",
    "6. Try different initializations of other bits in real_obs\n",
    "7. Random vector projection?"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Fix\n",
    "\n",
    "Construct Rule(id=0, ranges=[src_ip_start, src_ip_end, dst_ip_start, dst_ip_end, src_port_start, src_port_end, dst_port_start, dst_port_end, proto_start, proto_end])\n",
    "\n",
    "Call rule.get_state()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "864\n",
      "268435456\n"
     ]
    }
   ],
   "source": [
    "rules = load_rules_from_file(\"classbench/fw5_1k\")\n",
    "# rules = load_rules_from_file(\"classbench/acl5_1k\")\n",
    "X = np.arange(0, 2**32, 2**28)\n",
    "Y = np.arange(0, 2**32, 2**28)\n",
    "N = len(X)\n",
    "r = rules[0]\n",
    "print(len(rules))\n",
    "print(X[1])\n",
    "# print(rules[0].ranges)\n",
    "# print(rules[100].ranges)\n",
    "# print(rules[200].ranges)\n",
    "# print(rules[300].ranges)\n",
    "# print(rules[400].ranges)\n",
    "# for i in range(N - 1):\n",
    "#     for j in range(N - 1):\n",
    "#         src_ip_range = [X[i], X[i + 1]]\n",
    "#         dst_ip_range = [Y[i], Y[i + 1]]\n",
    "#         if src_ip_range[0] < r.ranges[0] < src_ip_\n",
    "\n",
    "# x_pts = [r.ranges[0], r.ranges[1]]\n",
    "# y_pts = [r.ranges[2], r.ranges[3]]\n",
    "# plt.scatter(x_pts, y_pts)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [],
   "source": [
    "def intersect(sx1, sx2, sy1, sy2, ox1, ox2, oy1, oy2):\n",
    "    return (sx1 < ox2 and sx2 > ox1) and (sy1 < oy2 and sy2 > oy1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "4294967296\n",
      "4294967296\n",
      "268435456\n"
     ]
    }
   ],
   "source": [
    "src_diff = [r.ranges[1] - r.ranges[0] for r in rules]\n",
    "dst_diff = [r.ranges[3] - r.ranges[2] for r in rules]\n",
    "print(max(src_diff))\n",
    "print(max(dst_diff))\n",
    "print(2**28)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 84. 105.  75.  75. 128.  84.  84. 124. 133.  87.  88. 118. 125.  89.\n",
      "  120.]\n",
      " [ 85. 110.  77.  77. 132.  88.  88. 128. 134.  88.  89. 119. 126.  90.\n",
      "  121.]\n",
      " [ 98. 120.  95.  90. 145. 101. 101. 141. 147. 101. 102. 132. 139. 103.\n",
      "  134.]\n",
      " [ 65.  87.  57.  57. 112.  68.  68. 108. 121.  75.  76. 106. 113.  77.\n",
      "  108.]\n",
      " [100. 122.  99.  92. 151. 103. 103. 139. 145.  99. 100. 130. 137. 101.\n",
      "  132.]\n",
      " [ 65.  87.  64.  57. 112.  68.  68. 104. 121.  75.  76. 106. 113.  77.\n",
      "  108.]\n",
      " [ 65.  87.  64.  57. 112.  68.  68. 104. 121.  75.  76. 106. 113.  77.\n",
      "  108.]\n",
      " [ 96. 118.  95.  88. 144. 100. 100. 142. 143.  97.  98. 128. 135.  99.\n",
      "  130.]\n",
      " [ 86. 131. 121.  87. 133.  89.  89. 125. 120.  91.  84.  84. 129.  93.\n",
      "  132.]\n",
      " [ 87. 132. 122.  88. 134.  90.  90. 126. 120.  95.  87.  87. 132.  96.\n",
      "  135.]\n",
      " [ 71. 116. 106.  72. 118.  74.  74. 110. 100.  74.  67.  67. 112.  76.\n",
      "  115.]\n",
      " [ 92. 137. 127.  93. 139.  95.  95. 131. 132. 106.  99. 104. 144. 108.\n",
      "  147.]\n",
      " [ 94. 139. 129.  95. 141.  97.  97. 133. 136. 110. 103. 111. 152. 114.\n",
      "  145.]\n",
      " [ 71. 116. 106.  72. 118.  74.  74. 110. 100.  74.  67.  75. 112.  76.\n",
      "  107.]\n",
      " [ 83. 128. 118.  84. 130.  86.  86. 122. 117.  91.  84.  92. 129.  93.\n",
      "  127.]]\n"
     ]
    }
   ],
   "source": [
    "num_rules = np.zeros((N-1, N-1))\n",
    "for r in rules:\n",
    "    for i in range(N-1):\n",
    "        for j in range(N-1):\n",
    "            if intersect(r.ranges[0], r.ranges[1], r.ranges[2], r.ranges[3], X[i], X[i+1], Y[j], Y[j+1]):\n",
    "                num_rules[i, j] += 1\n",
    "\n",
    "print(num_rules)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]\n",
      "257\n",
      "[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0]\n"
     ]
    }
   ],
   "source": [
    "def make_binary_list(num):\n",
    "    b = \"{0:b}\".format(int(num))\n",
    "    lst = [float(d) for d in b]\n",
    "    diff = 32 - len(lst)\n",
    "    lst = [0.0]*diff + lst\n",
    "    return lst\n",
    "def make_dec(ip):\n",
    "    ip_str = ''.join(str(int(e)) for e in ip)\n",
    "    ip_dec = int(ip_str, 2)\n",
    "    return ip_dec\n",
    "i = 2**8 + 1\n",
    "b = make_binary_list(i)\n",
    "print(b)\n",
    "print(make_dec(b))\n",
    "b = list(bin(int(i))[2:])\n",
    "l = [0.0] * (32 - len(b)) + [float(i) for i in b]\n",
    "print(l)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {},
   "outputs": [],
   "source": [
    "### Get values ###\n",
    "def value(policy, obs):\n",
    "    feed_dict = {\n",
    "       policy.observations: obs,\n",
    "    }\n",
    "    vf = policy.sess.run(policy.value_function, feed_dict)\n",
    "    return vf\n",
    "\n",
    "# values_lst = value(agent.get_policy(), obs_lst)\n",
    "# values = values_lst.reshape((N, N))\n",
    "# print(values[30][30])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "metadata": {},
   "outputs": [],
   "source": [
    "def generate_obs_and_vals(agent):\n",
    "    max_ip = 2**32\n",
    "    max_port = 2**16\n",
    "    max_proto = 2**8\n",
    "    interval = 2**28\n",
    "    X = np.arange(0, max_ip, interval)\n",
    "    Y = np.arange(0, max_ip, interval)\n",
    "    N = len(X)\n",
    "    obs_lst = []\n",
    "\n",
    "    for i in range(N-1): \n",
    "        for j in range(N-1):\n",
    "#             [src_ip_start, src_ip_end, dst_ip_start, dst_ip_end, src_port_start, src_port_end, dst_port_start, dst_port_end, proto_start, proto_end]\n",
    "#             src = make_binary_list(X[i])\n",
    "#             dst = make_binary_list(Y[j])\n",
    "#             size = 279 - 64\n",
    "#             if mask is None:\n",
    "#                 mask = [0.0] * size\n",
    "#             real_obs = src + dst + mask\n",
    "            ranges = [X[i], X[i+1], Y[j], Y[j+1], 0, max_port, 0, max_port, 0, 2**8]\n",
    "            node = Node(0, ranges, [], 0, None, None)\n",
    "            real_obs = node.get_state()\n",
    "            action_mask = [0.0] * 10\n",
    "            obs = {\"real_obs\": real_obs, \"action_mask\": action_mask}\n",
    "            _obs = agent.local_evaluator.preprocessors[\"default\"].transform(obs)\n",
    "            obs_lst.append(_obs)\n",
    "#     print(obs_lst)\n",
    "    values_lst = value(agent.get_policy(), obs_lst)\n",
    "    values = values_lst.reshape((N-1, N-1))\n",
    "    return X, Y, values"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQ0AAAEWCAYAAAB8A8JQAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDMuMC4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvOIA7rQAAFthJREFUeJzt3Xm0nVV5x/Hvj0xAEoZAwiwBBCxkKcMFUSkiEUREoCxboCKp2AUsi4LVytSqtasV1OVAscUUrFDDsGTWhUIqTihDQwwQDGMIEoYkzAmCkPD0j/e94XBz783Z+81533PC77PWXfcMe5/9nPec+9z9DntvRQRmZu1ap+kAzKy3OGmYWRInDTNL4qRhZkmcNMwsiZOGmSVx0ljLSDpT0gVNx2FrL/k6jd4iaVnL3fWBPwEryvsnRsSMBmL6PrAwIv6x7rbL9kcDdwHjImLr8rHJwMPA7yJij5aymwKPA49HxOTag10LuKfRYyJiXP8P8Afgwy2P1Z4wusQ/AIuHeG6spCkt9/+aIplYJieNtYykL0n6QXl7sqSQ9HFJj0p6VtJJkvaSdJek5ySdN6D+8ZLmlWVvkLRt+bgkfVPSYknPl/WnSDoB+CjweUnLJP2oLL+lpCslLZH0sKRPD4jxCkmXS1oqabakd7Q8f5qkx8rn7pM0dZj3ux1wLPCVIYr8DzCt5f5xwMUp29TeyEnjzeGdwI7AUcC3gLOA9wO7An8l6b0Ako4AzgSOBCYCvwYuLV/jIGA/YCdgo/K1no6I6cAM4Ktlb+fDktYBfgTcCWwFTAVOlfSBlpgOB34ITAAuAa6RNErSzsDJwF4RMR74ALBgmPf272XMLw3x/A+AoyWNkPRnwHjgtuE3lw3HSePN4V8i4uWIuBF4Ebg0IhZHxGMUiWH3styJwFciYl5ELAf+Ddit7G28SvEH9zaKY2HzIuKJIdrbC5gYEV+OiFciYj7wX8DRLWXuiIgrIuJV4BvAusA+FMdnxgC7SBoVEQsi4qHBGpH0F8DIiLh6mPe+ELiPIklOw72Mypw03hwWtdx+aZD748rb2wLfLndbngOeAQRsFRE3AecB3wEWSZouaYMh2tsW2LL/dcrXOhPYrKXMo/03IuI1ij/uLSPiQeBU4EvAYkmXSdpyYAOSxgJfBT7Vxvu/GPgb4BiKnodV4KRhrR6lOAOzUcvPehHxW4CIODci9qTYrdmJ4gAkwMBTcI8CDw94nfERcUhLmW36b5S7M1tTnNUgIi6JiH0pkk8A5wwS647AZODXkp4ErgK2kPRkeeak1ZXAh4D5EfFIygaxVTlpWKvzgTMk7QogaUNJf1ne3kvSOyWNotjFeZnXT/UuArZveZ3bgRfKA5rrlccTpkjaq6XMnpKOlDSSomfxJ+BWSTtLOkDSmLKNl1raaTWXIvHsVv78bRnHbrT0YgAi4kXggLKMVeSkYSuVxwbOAS6T9ALFH+YHy6c3oDgu8SzwCPA08PXyuQspjkE8J+maiFgBfJjiD/hh4CngAmDDluaupTiY+izwMeDI8vjGGODsss6TwCSKXZuBsS6PiCf7fyh2pV4r76+SZCJi1lDHRiyNL+6y2kn6EvDWiDi26VgsnXsaZpbEScPMknj3xMySuKdhZklGNh1AOzadoJi8VUbFwU7Uteu1CnVfzaw3okKbyyvUzZX7PjdbfZEh5X6mVTrUue9zTIU2a36fCxbCU8+E2inbE0lj8lYw65qMis9VaPTlCnWfzKw31PWV7Xg6s16V5Jj7Pj9Toc2lmfWqfJ5LMuttW6HN3PeZmeD6Dm2/rHdPzCyJk4aZJelY0pD0vXLuhbmDPPe5cp6HTTvVvpl1Rid7Gt8HDh74oKRtgAMpZp0ysx7TsaQREb+iGA8w0DeBz1PteLaZNaTWYxqSDgMei4g762zXzNac2k65SlqfYpq5g9osfwJwAsBbVpmCxcyaUmdPYwdgO+BOSQsoJl2ZLWnzwQpHxPSI6IuIvokTaozSzIZVW08jIu6mmBsBgDJx9EXEU3XFYGbVdfKU66XALcDOkhZK+kSn2jKz+nSspxERx6zm+cmdatvMOsdXhJpZEicNM0vSE6NcGbMn7DAro+IqV7AnqDLW/I7MeuNWX2RIuZe+VBm/nbtQ2Yn5TW6wILNehWGuk3LnI94hv81xuW1m/kmPvqLtou5pmFkSJw0zS+KkYWZJnDTMLImThpklcdIwsyROGmaWxEnDzJI4aZhZEicNM0vipGFmSZw0zCyJk4aZJemNUa5L74BftLU27RvlrsEJsG6Fuo9l1vtjhTZz3+v4Cm0+nlnvCz/JbzN3fd4qn2fumrVV2sx9n2Mz6yV899zTMLMkThpmlsRJw8yS1LoAtKSvSbpX0l2Srpa0UafaN7POqHsB6JnAlIh4O3A/cEYH2zezDqh1AeiIuDEi+iffvJVilTUz6yFNHtM4Hqhw7s3MmtBI0pB0FsV03zOGKXOCpFmSZi15vr7YzGx4tScNSdOAQ4GPRkQMVe4NC0BvWF98Zja8Wq8IlXQwcBrw3oiocv2jmTWk7gWgz6O4cHmmpDmSzu9U+2bWGXUvAH1hp9ozs3r4ilAzS+KkYWZJNMwJjK7xNily9msmVmjzlgp1c0/2LK3Q5iaZ9WZXaHP9zHrTKrSZO9r83gptjs6sV+X7Nyqz3vzMescB8yLamn/CPQ0zS+KkYWZJnDTMLImThpklcdIwsyROGmaWxEnDzJI4aZhZEicNM0vipGFmSZw0zCyJk4aZJXHSMLMkPbEA9EjyRgyOqNBmX4W6r9Zcr4r3Vqj7cma9Kutyr8isV2Wd69x5KV+o0Gau3BHWKX8r7mmYWRInDTNL4qRhZknqXgB6gqSZkh4of2/cqfbNrDPqXgD6dOBnEbEj8LPyvpn1kFoXgAYOBy4qb18EHNGp9s2sM+o+prFZRDwBUP6eVHP7ZlZR1x4IbV0A+tmmgzGzlepOGoskbQFQ/l48VMHWBaB9tNSse9SdNK7j9WUvpgHX1ty+mVVU9wLQZwMHSnoAOLC8b2Y9pO4FoAGmdqpNM+u8rj0QambdyUnDzJL0xND4dXeCnb6bUfHJCo2+VqHuY5n1clc3BliUWS93rDnA45n1tq3QZu64+txVnCH/e1RlBeiBl0W2a0xetXV/1H5Z9zTMLImThpklcdIwsyROGmaWxEnDzJI4aZhZEicNM0vipGFmSZw0zCyJk4aZJXHSMLMkThpmlsRJw8yS9MQo17gfXnlfer3nKrRZZcBp7uDP3AWVIf+9VnmfuYM/jxiX3+aKZXn1RlRo88XMNqtYmlkvdwHolEHd7mmYWRInDTNL4qRhZkkaSRqSPiPpHklzJV0qqcqutZnVqPakIWkr4NNAX0RMAUYAR9cdh5nlaWr3ZCSwnqSRwPrkn3Aws5rVnjQi4jHg68AfgCeA5yPixrrjMLM8TeyebAwcDmwHbAmMlXTsIOVWLgD9VN1BmtmQmtg9eT/wcEQsiYhXgauAdw8s1LoA9Ka1h2hmQ2nrilBJRwL7AgHcHBFXV2jzD8A+ktYHXqJYpnFWhdczsxqttqch6T+Ak4C7gbnAiZK+k9tgRNwGXAHMLl9zHWB67uuZWb3a6Wm8F5gSEQEg6SKKP/ZsEfFF4ItVXsPMmtHOMY37gLe03N8GuKsz4ZhZt2unp7EJME/S7eX9vYBbJF0HEBGHdSo4M+s+7SSNL3Q8itXQnhMZPesjyfUmcW+FVvPHUm/AfZk1d8huk+w2N6/Q5tzMelOzWxzBI5k18z/PsSzIrLlrhTZz3+dmWbXW6Wv/XMRqk0ZE/DIrCjNbKw2ZNCTdHBH7SlpKcap15VNARMQGHY/OzLrOkEkjIvYtf4+vLxwz63aeT8PMkjhpmFkSJw0zS9LOZeTbtc6sJWk9SZM7GZSZda92eho/5I0znK8oHzOzN6F2ksbIiHil/055e3TnQjKzbtZO0lgiaeWl4pIOBzwvjtmbVDuXkZ8EzJB0Xnl/IfCxzoVkZt1s2KQhaR1gz4jYR9I4QBGRu2Kcma0Fht09iYjXgJPL28ucMMxM5dw6QxeQ/oliWr7LgRf7H4+IZzob2uv6dlLMypkrLHeFYoAqF8/nLsiwfoU2F2XWy10xGIod1RyfrtDm05n1xlZoc0lmvQkV2nw+s17md6jvSJg1N9RO2XaOaRxf/v67lscC2D41MDPrfe0Mjd+ujkDMrDcMeUxD0l6SNm+5f5ykayWdK6lKx8vMethwB0K/C7wCIGk/4GzgYoq9rUqzh0vaSNIVku6VNE/Su6q8npnVZ7jdkxEtBzuPAqZHxJXAlZLmVGz328BPI+IjkkZT7RCgmdVouJ7GiHKBZigmdbyp5bm2FlkajKQNgP2AC6G4LD0inst9PTOr13B//JcCv5T0FMUp118DSHor+SeEoDjrsgT4b0nvAO4ATomIF4evZmbdYMieRkT8K/BZ4PvAvvH6BR3rAJ+q0OZIYA/gPyNid4prP04fWKh1AeglVVKUma1Rw+5mRMStgzx2f8U2FwILy+UZoViicZWkERHTKQ+49u2k4a9AM7Pa1D5zV0Q8CTwqaefyoanA7+uOw8zyZB/QrOhTFCNnRwPzgY83FIeZJWokaUTEHKCvibbNrBpPLGxmSZw0zCxJU8c00mwwEg7MGO7y1OIKbeZX5YHMeuuuvsiQ5mfWqzI0PncbVbn+N3dGl1EV2hyRWe/lCm2+UKFujtdWX6SfexpmlsRJw8ySOGmYWRInDTNL4qRhZkmcNMwsiZOGmSVx0jCzJE4aZpbEScPMkjhpmFkSJw0zS+KkYWZJemOU65zlsEn6iNVXKixRPbpCOn0sYcRgq9zBlJC/RnGVAae561z/+fsqNJq72EXmZwI0s+h07mjeXAlfIPc0zCyJk4aZJXHSMLMkjSUNSSMk/U7Sj5uKwczSNdnTOAWY12D7ZpahkaQhaWvgQ8AFTbRvZvma6ml8C/g81U6EmVkDak8akg4FFkfEHasp9/oC0F7J1axrNNHTeA9wmKQFwGXAAZJ+MLBQREyPiL6I6JuoukM0s6E0sQD0GRGxdURMBo4GboqIY+uOw8zy+DoNM0vS6NiTiPgF8IsmYzCzNO5pmFkSJw0zS9IbQ+NHAOPTq1UZ3l5laPLEP+XVG11hnPrEP+bVq7LOcPZ61blj6gFWZNarshhzE1cT5X4XXs2sl3CG0j0NM0vipGFmSZw0zCyJk4aZJXHSMLMkThpmlsRJw8ySOGmYWRInDTNL4qRhZkmcNMwsiZOGmSVx0jCzJIro/ll7N5Cir+Y2cwcLVqn7SoU2c1V5n7mDP6us/5y7SHbu4FjI30ajKrSZ+z5zY70CWBzR1lhX9zTMLImThpklcdIwsyRNLJa0jaSfS5on6R5Jp9Qdg5nla2K6v+XAZyNitqTxwB2SZkbE7xuIxcwSNbFY0hMRMbu8vZRi5fit6o7DzPI0ekxD0mRgd+C2JuMws/Y1Nhu5pHHAlcCpEbHKpNiSTgBOABhTc2xmNrRGehqSRlEkjBkRcdVgZVoXgB5db3hmNowmzp4IuBCYFxHfqLt9M6umiZ7Ge4CPAQdImlP+HNJAHGaWofZjGhFxM0nrOZlZN/EVoWaWxEnDzJL0xALQOwI/zaj3XIU2c4cmAzydWa/KOsO577XK8O1nMutVWOc6e13uKp9n7rYdW6HN3PeZ+3nemFDWPQ0zS+KkYWZJnDTMLImThpklcdIwsyROGmaWxEnDzJI4aZhZEicNM0vipGFmSZw0zCyJk4aZJXHSMLMkPTHK9X5gaka93JGC0MzozyrqHhUJ+aM/31+hzZcz61UZ5frHzHpV/iPnLuSc+z4XJZR1T8PMkjhpmFkSJw0zS9LUuicHS7pP0oOSTm8iBjPL08S6JyOA7wAfBHYBjpG0S91xmFmeJnoaewMPRsT8iHgFuAw4vIE4zCxDE0ljK+DRlvsL8arxZj2jies0BlsoKVYp5AWgzbpSEz2NhcA2Lfe3Bh4fWKh1AegqFyCZ2ZrVRNL4P2BHSdtJGg0cDVzXQBxmlqGJtVyXSzoZuIHiqtfvRcQ9dcdhZnkaGXsSEdcD1zfRtplV4ytCzSyJk4aZJVHEKmc7u46kJcAjQzy9KfBUjeGsTrfFA90Xk+MZXhPxbBsRE9sp2BNJYziSZkVEX9Nx9Ou2eKD7YnI8w+u2eAby7omZJXHSMLMka0PSmN50AAN0WzzQfTE5nuF1Wzxv0PPHNMysXmtDT8PMauSkYWZJeiZprG6KQEljJF1ePn+bpMkdjGUbST+XNE/SPZJOGaTM/pKelzSn/PlCp+JpaXOBpLvL9mYN8rwknVtuo7sk7dHBWHZuee9zJL0g6dQBZTq6jSR9T9JiSXNbHpsgaaakB8rfGw9Rd1pZ5gFJ0zoYz9ck3Vt+HldL2miIusN+trWKiK7/oRjY9hCwPTAauBPYZUCZTwLnl7ePBi7vYDxbAHuUt8dTLM0yMJ79gR/XvJ0WAJsO8/whwE8o5jTZB7itxs/vSYoLiGrbRsB+wB7A3JbHvgqcXt4+HThnkHoTgPnl743L2xt3KJ6DgJHl7XMGi6edz7bOn17pabQzReDhwEXl7SuAqZIGm/Cnsoh4IiJml7eXAvPojdnHDgcujsKtwEaStqih3anAQxEx1FW9HRERv2LVtatavycXAUcMUvUDwMyIeCYingVmAgd3Ip6IuDEilpd3b6WYX6ar9UrSaGeKwJVlyg/heWCTTgdW7gbtDtw2yNPvknSnpJ9I2rXTsVDMgHajpDvKmc8GamqqxaOBS4d4ru5ttFlEPAFF8gcmDVKmqe10PEVPcDCr+2xr0xPLMtLeFIFtTSO4JkkaB1wJnBoRLwx4ejZFd3yZpEOAa4AdOxkP8J6IeFzSJGCmpHvL/24rQx6kTqe30WjgMOCMQZ5uYhu1o4ntdBawHJgxRJHVfba16ZWeRjtTBK4sI2kksCEdXFZV0iiKhDEjIq4a+HxEvBARy8rb1wOjJG3aqXjKdh4vfy8GrqbYrWvV1lSLa9gHgdkRscpyoU1sI2BR/y5Z+XvxIGVq3U7lgdZDgY9GeQBjoDY+29r0StJoZ4rA64D+o9wfAW4a6gOoqjxWciEwLyK+MUSZzfuPqUjam2JbP92JeMo2xkoa33+b4gDb3AHFrgOOK8+i7AM8399V76BjGGLXpO5tVGr9nkwDrh2kzA3AQZI2Ls+uHFQ+tsZJOhg4DTgsIgZda7rNz7Y+TR+JbfeH4sj//RRnUc4qH/syxcYGWBf4IfAgcDuwfQdj2Zeiu3oXMKf8OQQ4CTipLHMycA/FmZ5bgXd3ePtsX7Z1Z9lu/zZqjUkUC1U9BNwN9HU4pvUpksCGLY/Vto0oktUTFIuwLwQ+QXGc62fAA+XvCWXZPuCClrrHl9+lB4GPdzCeBymOn/R/j/rPAG4JXD/cZ9vUjy8jN7MkvbJ7YmZdwknDzJI4aZhZEicNM0vipGFmSZw0bFiSVpQjK+8pL/f+e0lDfm8kbSTpk8M8/9vORGp18SlXG5akZRExrrw9CbgE+E1EfHGI8pMpRq5OqS1Iq5V7Gta2KC5hPgE4ubyqdFdJt5c9kbsk7QicDexQPva1ga8haVn5e39JvyrnkPi9pPOH68FY9+iVAWvWJSJifvnHPYni6s5vR8SM8vL+ERRzVEyJiN3aeLm9gV0oFsL6KXAkxbQG1sWc2S1H/yjQW4AzJZ1GMVr1pcTXuT2KOVJWUFxive+aDNI6w0nDkkjaHlgBLI6ISyiGvb8E3CDpgMSXG3hAzQfYeoCThrVN0kTgfOC8iIgygcyPiHMpRo++HVhKMQViO/YuRy6vAxwF3NyJuG3NctKw1Vmv/5Qr8L/AjcA/l88dBcyVNAd4G8VUgk8Dv5E0d7ADoQPcQnHgdC7wMMU8EdblfMrVGiFpf+BzEXFo07FYGvc0zCyJexpmlsQ9DTNL4qRhZkmcNMwsiZOGmSVx0jCzJP8PX9k70cfjpUUAAAAASUVORK5CYII=\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "### Visualize ###\n",
    "def visualize(agent, num):\n",
    "    X, Y, values = generate_obs_and_vals(agent)\n",
    "    plt.imshow(values, cmap='hot', interpolation='nearest', origin='lower')\n",
    "#     _X, _Y = np.meshgrid(X, Y)\n",
    "#     plt.contour(_X, _Y, values)\n",
    "    plt.title(\"Timesteps {}\".format(num))\n",
    "    plt.xlabel(\"Dst ip\")\n",
    "    plt.ylabel(\"Src ip\")\n",
    "    plt.show()\n",
    "    \n",
    "visualize(agent_1, \"1\")\n",
    "visualize(agent_1M, \"1M\")\n",
    "visualize(agent_2M, \"2M\")\n",
    "visualize(agent_4M, \"4M\")\n",
    "visualize(agent_8M, \"8M\")\n",
    "# Yellow = high\n",
    "# Green = medium\n",
    "# Blue = low"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.image.AxesImage at 0x1d84929978>"
      ]
     },
     "execution_count": 45,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.imshow(num_rules, cmap='hot', interpolation='nearest', origin='lower')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
